package com.zn.net
{
    import com.zn.loading.LoaderMax;
    import com.zn.log.Log;

    import flash.events.ErrorEvent;
    import flash.events.Event;
    import flash.events.IOErrorEvent;
    import flash.events.SecurityErrorEvent;
    import flash.events.TimerEvent;
    import flash.net.URLLoader;
    import flash.net.URLRequest;
    import flash.net.URLRequestMethod;
    import flash.utils.Timer;

    /**
     *HTTP方式通信
     * @author zn
     *
     */
    public class HttpRequest
    {
        /**
         *轮询间隔时间
         */
        private static const DEFAULT_POLLING_INTERVAL:int = 3000;

        public static var rootUrl:String="";

        /**
         *已请求的方法，但是服务器还未返回
         * key:方法名
         */
        public static var requestDic:Object = {};

        private var _urlLoader:URLLoader;

        private var _url:String;

        private var _extraParams:String;

        private var _body:*;

        public var completeCallback:Function;

        public var requestProcessedCallback:Function;

        public var errorCallback:Function;

        public var ioErrorCallback:Function;

        public var securityErrorCallback:Function;

        /**
         *是否可以轮询
         */
        private var _pollingEnabled:Boolean = false;

        private var _pollingInterval:uint = DEFAULT_POLLING_INTERVAL;

        private var _timer:Timer;

        /**
         *是否已经初始化完成，准备完成
         */
        private var _ready:Boolean;

        private var _urlRequest:URLRequest;

        /**
         *是否已返回，防止因轮询而发生的重复请求
         */
        private var _isResult:Boolean = true;

        /**
         *是否可以连续请求，不用等待服务器返回
         */
        private var _concurrent:Boolean = false;

        /**
         *是否打印返回结果
         */
        private var _showResult:Boolean = true;

        public function HttpRequest(url:String,
                                    extraParams:String = "",
                                    pollingEnabled:Boolean = false,
                                    concurrent:Boolean = false,
                                    showResult:Boolean = true,
                                    completeCallback:Function = null,
                                    requestProcessedCallback:Function = null,
                                    errorCallback:Function = null,
                                    ioErrorCallback:Function = null,
                                    securityErrorCallback:Function = null)
        {
            _url = url;
            _extraParams = extraParams;

            _concurrent = concurrent;
            _showResult = showResult;
            _pollingEnabled = pollingEnabled;

            this.completeCallback = completeCallback;
            this.requestProcessedCallback = requestProcessedCallback;
            this.errorCallback = errorCallback;
            this.ioErrorCallback = ioErrorCallback;
            this.securityErrorCallback = securityErrorCallback;

            _urlLoader = new URLLoader();
            _urlLoader.addEventListener(ErrorEvent.ERROR, errorHandler);
            _urlLoader.addEventListener(IOErrorEvent.IO_ERROR, ioErrorHandler);
            _urlLoader.addEventListener(SecurityErrorEvent.SECURITY_ERROR, securityErrorHandler);
            _urlLoader.addEventListener(Event.COMPLETE, completeHandler);

        }

        public static function send(url:String,
                                    extraParams:String = "",
                                    pollingEnabled:Boolean = false,
                                    concurrent:Boolean = false,
                                    showResult:Boolean = true,
                                    completeCallback:Function = null,
                                    requestProcessedCallback:Function = null,
                                    errorCallback:Function = null,
                                    ioErrorCallback:Function = null,
                                    securityErrorCallback:Function = null):HttpRequest
        {
            var httpRequest:HttpRequest = new HttpRequest(url,
                                                          extraParams,
                                                          pollingEnabled,
                                                          concurrent,
                                                          showResult,
                                                          completeCallback,
                                                          requestProcessedCallback,
                                                          errorCallback,
                                                          ioErrorCallback,
                                                          securityErrorCallback);
            return httpRequest;
        }

        protected function errorHandler(event:ErrorEvent):void
        {
            Log.error(HttpRequest, "errorHandler", event.text);
            callEventCallback(errorCallback, event);
            close();
        }

        protected function ioErrorHandler(event:ErrorEvent):void
        {
            Log.error(HttpRequest, "ioErrorHandler", event.text);
            callEventCallback(ioErrorCallback, event);
            close();
        }

        protected function securityErrorHandler(event:SecurityErrorEvent):void
        {
            Log.error(HttpRequest, "securityErrorHandler", event.text);
            callEventCallback(securityErrorCallback, event);
            close();
        }

        protected function completeHandler(event:Event):void
        {
            _body = _urlLoader.data;

            if (_showResult)
            {
                Log.debug(HttpRequest, "completeHandler", "\n	服务器返回：" + fullURL +
                          "\n	参数：" + _extraParams +
                          "\n	数据：" + _body);
            }

            if (completeCallback != null)
            {
                try
                {
                    completeCallback(_body);
                }
                catch (e:Error)
                {
                    Log.error(HttpRequest, "completeHandler", e.message);
                }
            }

            if (!_pollingEnabled)
                close();

            delete requestDic[_url];
            _isResult = true;
        }

        /**
         *加载，请求
         *
         */
        public function load():void
        {
            if (requestDic[_url] && !_concurrent)
                return;

            if (_isResult)
            {
                if (!_ready)
                {
                    _urlRequest = new URLRequest(fullURL);
                    _urlRequest.method = URLRequestMethod.POST;
                    LoaderMax.setRequestURL(_urlRequest, fullURL, _extraParams);
                    _ready = true;

                    if (pollingEnabled)
                        startPoll();

                    _urlLoader.load(_urlRequest);
                    if (!_concurrent)
                        requestDic[_url] = true;
                }
                else
                {
                    _urlLoader.load(_urlRequest);
                    if (!_concurrent)
                        requestDic[_url] = true;
                }
            }

            _isResult = false;
        }

        /**
         *释放
         *
         */
        public function close():void
        {
            stopPoll();

            _urlLoader.removeEventListener(ErrorEvent.ERROR, errorHandler);
            _urlLoader.removeEventListener(IOErrorEvent.IO_ERROR, ioErrorHandler);
            _urlLoader.removeEventListener(SecurityErrorEvent.SECURITY_ERROR, securityErrorHandler);
            _urlLoader.removeEventListener(Event.COMPLETE, completeHandler);
            _urlLoader.close();
            _urlLoader = null;

            _isResult = true;
            delete requestDic[_url];
        }

        private function callEventCallback(callback:Function, params:*):void
        {
            if (callback != null)
                callback(params);
        }

        public function get body():Object
        {
            return _body;
        }

        public function get fullURL():String
        {
            return rootUrl + _url;
        }

        public function get pollingEnabled():Boolean
        {
            return _pollingEnabled;
        }

        public function set pollingEnabled(value:Boolean):void
        {
            _pollingEnabled = value;

            if (value)
            {
                startPoll();
            }
            else
            {
                stopPoll();
            }
        }

        private function stopPoll():void
        {
            if (_timer)
            {
                _timer.stop();
                _timer.removeEventListener(TimerEvent.TIMER, internalPoll);
                _timer = null;
            }
        }


        private function startPoll():void
        {
            if (!_timer)
            {
                _timer = new Timer(_pollingInterval, 0);
                _timer.addEventListener(TimerEvent.TIMER, internalPoll);
            }

            if (_ready)
                _timer.start();
        }


        protected function internalPoll(event:Event):void
        {
            load();
        }

        public function get pollingInterval():uint
        {
            return _pollingInterval;
        }

        public function set pollingInterval(value:uint):void
        {
            if (_pollingInterval == value)
                return;

            _pollingInterval = value;

            stopPoll();
            if (pollingEnabled)
                startPoll();
        }
    }
}
